Micron Document
🎖️GitЯра🎖️

Commit c32d370f6ad7ac37d7793c91d871efdf2fc52a47


Parents : a871dad
Author : James Rich <2199651+jamesarich@users.noreply.github.com>
Signature : Signature validation error
Date : 2026-05-21T12:56:20-07:00
Committer : GitHub <noreply@github.com>
Date : 2026-05-21T14:56:20-05:00

ai: Add spec kit agent governance extension and related files (#5568)

Changes

36 files changed, 1856 insertions(+), 146 deletions(-)

M AGENTS.md -1

Diff

diff --git a/.github/agents/speckit.agent-governance.refresh.agent.md b/.github/agents/speckit.agent-governance.refresh.agent.md
new file mode 100644
index 0000000000..0916b88e5c
--- /dev/null
+++ b/.github/agents/speckit.agent-governance.refresh.agent.md
@@ -0,0 +1,48 @@
+---
+description: Generate or update the active agent governance file
+---
+
+
+<!-- Extension: agent-governance -->
+<!-- Config: .specify/extensions/agent-governance/ -->
+# Agent Governance Generate/Update
+
+## Input
+
+$ARGUMENTS
+
+## Output
+
+- Active agent platform governance file.
+- Managed `SPECKIT GOVERNANCE` section.
+- `.specify/memory/agent-governance.md`: internal cache.
+
+## Procedure
+
+1. Require `.specify/`.
+2. Resolve target:
+ - `.specify/init-options.json` `context_file`
+ - `.specify/integration.json` `default_integration` or `integration`
+ - `AGENTS.md`
+3. Create internal cache when missing.
+4. Generate target file when missing.
+5. Update only the managed section when target exists.
+6. Use existing managed section as refresh source.
+7. Distill detected repository areas into action rules.
+ - depth: 2
+ - include hidden and cache directories
+8. Preserve content outside managed markers.
+9. Preserve managed markers verbatim.
+10. Run:
+
+ ```bash
+ uv run python .specify/extensions/agent-governance/scripts/refresh_agent_governance.py
+ ```
+
+## Report
+
+- target governance file
+- generated or updated
+- review target
+- internal cache status
+- captured evidence when cache is created
\ No newline at end of file

diff --git a/.github/agents/speckit.git.validate.agent.md b/.github/agents/speckit.git.validate.agent.md
index dfd751f2af..3612dbaa62 100644
--- a/.github/agents/speckit.git.validate.agent.md
+++ b/.github/agents/speckit.git.validate.agent.md
@@ -29,20 +29,22 @@ The branch name must match one of these patterns:
1. **Sequential**: `^[0-9]{3,}-` (e.g., `001-feature-name`, `042-fix-bug`, `1000-big-feature`)
2. **Timestamp**: `^[0-9]{8}-[0-9]{6}-` (e.g., `20260319-143022-feature-name`)
+3. **Conventional prefix**: `^(feat|fix|chore|docs|build|ci|refactor|test|deps)/` (e.g., `feat/add-node-filter`, `fix/ble-reconnect`)
## Execution
If on a feature branch (matches either pattern):
- Output: `✓ On feature branch: <branch-name>`
-- Check if the corresponding spec directory exists under `specs/`:
+- For sequential/timestamp branches, check if the corresponding spec directory exists under `specs/`:
- For sequential branches, look for `specs/<prefix>-*` where prefix matches the numeric portion
- For timestamp branches, look for `specs/<prefix>-*` where prefix matches the `YYYYMMDD-HHMMSS` portion
+- For conventional prefix branches, skip spec directory lookup (not spec-driven)
- If spec directory exists: `✓ Spec directory found: <path>`
- If spec directory missing: `⚠ No spec directory found for prefix <prefix>`
If NOT on a feature branch:
- Output: `✗ Not on a feature branch. Current branch: <branch-name>`
-- Output: `Feature branches should be named like: 001-feature-name or 20260319-143022-feature-name`
+- Output: `Feature branches should be named like: 001-feature-name, feat/feature-name, or 20260319-143022-feature-name`
## Graceful Degradation

diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index 0d5c633539..f6f0e772ac 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -1,6 +1,6 @@
# Meshtastic Android — Copilot Instructions
-> **Full rules**: `AGENTS.md` is the source of truth. This file is a compact quick-reference for build commands and task naming. For architecture, conventions, and workflow details, consult `AGENTS.md` and the `.skills/` playbooks listed at the bottom.
+> **Full rules**: `AGENTS.md` is the source of truth. This file is a compact quick-reference for build commands and task naming. For architecture, conventions, and workflow details, consult `AGENTS.md` and the `.skills/` playbooks.
## Build, Test & Lint
@@ -46,33 +46,14 @@ KMP modules have different task names than pure-Android modules. Using the wrong
## Quick Reference
-- **Architecture**: KMP project (Android, Desktop, iOS). Business logic in `commonMain`; platform shells (`androidApp/`, `desktopApp/`) wire DI and host UI. See `AGENTS.md` and `.skills/kmp-architecture/`.
+- **Architecture**: KMP project (Android, Desktop, iOS). Business logic in `commonMain`; platform shells (`androidApp/`, `desktopApp/`) wire DI and host UI.
- **Flavors**: `fdroid` (OSS) / `google` (Maps + DataDog). Only one installable at a time (different signing keys).
-- **Verify before push**: Run `./gradlew spotlessApply detekt assembleDebug test allTests`, then confirm CI with `gh pr checks <PR>`.
-- **Strings**: `stringResource(Res.string.key)` — run `python3 scripts/sort-strings.py` after adding strings.
-- **Icons**: `MeshtasticIcons` (from `core/ui/icon/`), not `material.icons.Icons`.
-- **Error handling**: `safeCatching {}` (not `runCatching {}`) in coroutine code.
-- **Dispatchers**: `org.meshtastic.core.common.util.ioDispatcher`, not `Dispatchers.IO`.
-- **Navigation**: `MeshtasticNavDisplay` + `NavigationBackHandler` (not Android `BackHandler`).
-- **Protos**: `core/proto/` is a read-only git submodule. Never modify proto files.
-- **Branches**: Must start with `feat/`, `fix/`, `chore/`, `docs/`, `build/`, `ci/`, `refactor/`, `test/`, `deps/`, or a numeric spec prefix. Always branch off `origin/main`.
-<!-- SPECKIT START -->
-## Active Plan
+> See `AGENTS.md` for full rules (verify before push, branch naming, protos, coding conventions).
+> Contextual `.github/instructions/` files enforce conventions scoped to relevant source sets.
-- **Feature**: Reorder Bottom Navigation Tab Labels
-- **Plan**: `specs/20260520-153412-nav-tab-labels/plan.md`
-- **Branch**: `jamesarich/issue-5543-alignment-reorder-bottom-navigation-tab-91d55d`
+<!-- SPECKIT START -->
+For additional context about technologies to be used, project structure,
+shell commands, and other important information, read the current plan
<!-- SPECKIT END -->
-## Deeper Guidance
-
-Consult `.skills/` for detailed playbooks:
-- `.skills/project-overview/` — Full codebase map and bootstrap
-- `.skills/kmp-architecture/` — Source-set rules, expect/actual
-- `.skills/compose-ui/` — Adaptive UI, string resources
-- `.skills/navigation-and-di/` — Nav 3 & Koin patterns
-- `.skills/testing-ci/` — CI architecture, verification matrix
-- `.skills/implement-feature/` — Feature development workflow
-- `.skills/code-review/` — PR hygiene checklist
-- `.skills/speckit/` — Spec Kit SDD workflow, slash commands, constitution

diff --git a/.github/prompts/speckit.agent-governance.refresh.prompt.md b/.github/prompts/speckit.agent-governance.refresh.prompt.md
new file mode 100644
index 0000000000..0df335b5d3
--- /dev/null
+++ b/.github/prompts/speckit.agent-governance.refresh.prompt.md
@@ -0,0 +1,3 @@
+---
+agent: speckit.agent-governance.refresh
+---

diff --git a/.specify/extensions.yml b/.specify/extensions.yml
index 05a4c8c7b3..cb6ff22942 100644
--- a/.specify/extensions.yml
+++ b/.specify/extensions.yml
@@ -1,4 +1,5 @@
-installed: []
+installed:
+- agent-governance
settings:
auto_execute_hooks: true
hooks:
@@ -82,6 +83,13 @@ hooks:
prompt: Commit constitution changes?
description: Auto-commit after constitution update
condition: null
+ - extension: agent-governance
+ command: speckit.agent-governance.refresh
+ enabled: true
+ optional: true
+ prompt: Refresh agent governance after constitution changes?
+ description: Generates the active agent platform governance file
+ condition: null
after_specify:
- extension: git
command: speckit.git.commit
@@ -106,6 +114,13 @@ hooks:
prompt: Commit plan changes?
description: Auto-commit after implementation planning
condition: null
+ - extension: agent-governance
+ command: speckit.agent-governance.refresh
+ enabled: true
+ optional: true
+ prompt: Refresh agent governance after planning?
+ description: Keeps the active agent platform governance file aligned
+ condition: null
after_tasks:
- extension: git
command: speckit.git.commit
@@ -114,6 +129,13 @@ hooks:
prompt: Commit task changes?
description: Auto-commit after task generation
condition: null
+ - extension: agent-governance
+ command: speckit.agent-governance.refresh
+ enabled: true
+ optional: true
+ prompt: Refresh agent governance after task generation?
+ description: Keeps the active agent platform governance file aligned
+ condition: null
after_implement:
- extension: git
command: speckit.git.commit

diff --git a/.specify/extensions/.cache/catalog-metadata.json b/.specify/extensions/.cache/catalog-metadata.json
index fe47962156..cd9a4e0f3e 100644
--- a/.specify/extensions/.cache/catalog-metadata.json
+++ b/.specify/extensions/.cache/catalog-metadata.json
@@ -1,4 +1,4 @@
{
- "cached_at": "2026-05-09T17:19:49.660998+00:00",
+ "cached_at": "2026-05-21T18:06:13.258618+00:00",
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.json"
}
\ No newline at end of file

diff --git a/.specify/extensions/.registry b/.specify/extensions/.registry
index 3e225091c6..feace7de33 100644
--- a/.specify/extensions/.registry
+++ b/.specify/extensions/.registry
@@ -108,6 +108,23 @@
},
"registered_skills": [],
"installed_at": "2026-05-09T00:25:20.640435+00:00"
+ },
+ "agent-governance": {
+ "version": "1.2.0",
+ "source": "local",
+ "manifest_hash": "sha256:99b9bb818d30379426ffd15e31660bf7e762eb90d1cca22ebcd4dd27b78f94a2",
+ "enabled": false,
+ "priority": 10,
+ "registered_commands": {
+ "copilot": [
+ "speckit.agent-governance.refresh"
+ ],
+ "opencode": [
+ "speckit.agent-governance.refresh"
+ ]
+ },
+ "registered_skills": [],
+ "installed_at": "2026-05-21T18:07:24.505929+00:00"
}
}
-}
+}
\ No newline at end of file

diff --git a/.specify/extensions/agent-governance/.gitignore b/.specify/extensions/agent-governance/.gitignore
new file mode 100644
index 0000000000..d40d1eb935
--- /dev/null
+++ b/.specify/extensions/agent-governance/.gitignore
@@ -0,0 +1,7 @@
+__pycache__/
+*.pyc
+.pytest_cache/
+.DS_Store
+.venv/
+dist/
+*.zip

diff --git a/.specify/extensions/agent-governance/CHANGELOG.md b/.specify/extensions/agent-governance/CHANGELOG.md
new file mode 100644
index 0000000000..dab737d132
--- /dev/null
+++ b/.specify/extensions/agent-governance/CHANGELOG.md
@@ -0,0 +1,40 @@
+# Changelog
+
+## Unreleased
+
+## [1.2.0] - 2026-05-19
+
+### Changed
+
+- Initialize the missing governance evidence cache from repository evidence instead of copying the bundled template verbatim.
+- Document captured repository evidence and manifest-backed commands in the initial governance evidence cache.
+- Clarify that the extension generates active agent platform repository governance files from Spec Kit metadata.
+- Simplify command semantics to one generate/update command: missing target governance files are generated, existing target governance files are updated.
+- Include repository evidence and development commands in generated agent platform governance files.
+- Add `uv`/`pytest` development configuration so the repository test suite has a reproducible runner.
+- Treat the generated active agent platform section as the repository governance SSOT and `.specify/memory/agent-governance.md` as a first-run evidence cache.
+- Preserve reviewed governance content from an existing active generated section during refresh instead of re-reading rules from the memory cache.
+- Clarify that users review only the resolved active agent governance file; no separate memory review or second refresh is required.
+- Distill detected repository areas into generated action rules with depth limited to two directory levels, including hidden and cache directories.
+- Add generic directory responsibility governance without platform or project examples.
+- Tighten governance template wording to preserve managed markers, scope broad linked-file updates, and limit skill-spec field requirements to repository-local skills.
+
+## [1.1.0] - 2026-05-15
+
+### Changed
+
+- Decoupled the agent governance domain from specific project-governance source files.
+- Updated generated projections to describe project governance as an independent domain.
+
+### Added
+
+- Tests for template and projection domain boundaries.
+
+## [1.0.0] - 2026-05-14
+
+### Added
+
+- Initial `speckit.agent-governance.refresh` command.
+- Agent governance memory template.
+- Python helper to project managed governance sections into active agent context files.
+- Optional hooks after constitution, plan, and tasks workflows.

diff --git a/.specify/extensions/agent-governance/LICENSE b/.specify/extensions/agent-governance/LICENSE
new file mode 100644
index 0000000000..1fb116dbeb
--- /dev/null
+++ b/.specify/extensions/agent-governance/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 bigben
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

diff --git a/.specify/extensions/agent-governance/README.md b/.specify/extensions/agent-governance/README.md
new file mode 100644
index 0000000000..7feb90de94
--- /dev/null
+++ b/.specify/extensions/agent-governance/README.md
@@ -0,0 +1,58 @@
+# Spec Kit Agent Governance
+
+Generate the active agent platform governance SSOT section.
+
+## Output
+
+- Active target file from Spec Kit integration metadata.
+- Managed `SPECKIT GOVERNANCE` section.
+
+## Scope
+
+- Generate missing target governance file.
+- Update existing target governance file.
+- Distill detected repository areas into action rules.
+- Analyze repository areas to depth 2 only.
+- Include hidden and cache directories in repository area governance.
+- Enforce one primary responsibility per directory.
+- Preserve user-authored content outside managed markers.
+- Preserve managed markers verbatim.
+- Keep `.specify/memory/agent-governance.md` internal.
+- Review only the active target file.
+
+## Install
+
+```bash
+specify extension add agent-governance --from https://github.com/bigsmartben/spec-kit-agent-governance/archive/refs/tags/v1.2.0.zip
+```
+
+Local development:
+
+```bash
+specify extension add --dev /path/to/spec-kit-agent-governance
+```
+
+## Run
+
+```text
+/speckit.agent-governance.refresh
+```
+
+Helper:
+
+```bash
+uv run python .specify/extensions/agent-governance/scripts/refresh_agent_governance.py
+```
+
+## Files
+
+- `extension.yml`
+- `commands/speckit.agent-governance.refresh.md`
+- `scripts/refresh_agent_governance.py`
+- `templates/agent-governance-template.md`
+
+## Verify
+
+```bash
+uv run pytest -q
+```

diff --git a/.specify/extensions/agent-governance/commands/speckit.agent-governance.refresh.md b/.specify/extensions/agent-governance/commands/speckit.agent-governance.refresh.md
new file mode 100644
index 0000000000..0a4f20443b
--- /dev/null
+++ b/.specify/extensions/agent-governance/commands/speckit.agent-governance.refresh.md
@@ -0,0 +1,45 @@
+---
+description: "Generate or update the active agent governance file"
+---
+
+# Agent Governance Generate/Update
+
+## Input
+
+$ARGUMENTS
+
+## Output
+
+- Active agent platform governance file.
+- Managed `SPECKIT GOVERNANCE` section.
+- `.specify/memory/agent-governance.md`: internal cache.
+
+## Procedure
+
+1. Require `.specify/`.
+2. Resolve target:
+ - `.specify/init-options.json` `context_file`
+ - `.specify/integration.json` `default_integration` or `integration`
+ - `AGENTS.md`
+3. Create internal cache when missing.
+4. Generate target file when missing.
+5. Update only the managed section when target exists.
+6. Use existing managed section as refresh source.
+7. Distill detected repository areas into action rules.
+ - depth: 2
+ - include hidden and cache directories
+8. Preserve content outside managed markers.
+9. Preserve managed markers verbatim.
+10. Run:
+
+ ```bash
+ uv run python .specify/extensions/agent-governance/scripts/refresh_agent_governance.py
+ ```
+
+## Report
+
+- target governance file
+- generated or updated
+- review target
+- internal cache status
+- captured evidence when cache is created

diff --git a/.specify/extensions/agent-governance/extension.yml b/.specify/extensions/agent-governance/extension.yml
new file mode 100644
index 0000000000..d9ee1da34a
--- /dev/null
+++ b/.specify/extensions/agent-governance/extension.yml
@@ -0,0 +1,46 @@
+schema_version: "1.0"
+
+extension:
+ id: agent-governance
+ name: "Agent Governance"
+ version: "1.2.0"
+ description: "Generate agent-platform repository governance files from Spec Kit metadata"
+ author: "bigben"
+ repository: "https://github.com/bigsmartben/spec-kit-agent-governance"
+ homepage: "https://github.com/bigsmartben/spec-kit-agent-governance"
+ license: "MIT"
+
+requires:
+ speckit_version: ">=0.8.0"
+ tools:
+ - name: "uv"
+ required: true
+
+provides:
+ commands:
+ - name: "speckit.agent-governance.refresh"
+ file: "commands/speckit.agent-governance.refresh.md"
+ description: "Generate or update the active agent platform governance file"
+
+hooks:
+ after_constitution:
+ command: "speckit.agent-governance.refresh"
+ optional: true
+ prompt: "Refresh agent governance after constitution changes?"
+ description: "Generates the active agent platform governance file"
+ after_plan:
+ command: "speckit.agent-governance.refresh"
+ optional: true
+ prompt: "Refresh agent governance after planning?"
+ description: "Keeps the active agent platform governance file aligned"
+ after_tasks:
+ command: "speckit.agent-governance.refresh"
+ optional: true
+ prompt: "Refresh agent governance after task generation?"
+ description: "Keeps the active agent platform governance file aligned"
+
+tags:
+ - "governance"
+ - "agents"
+ - "memory"
+ - "context"

diff --git a/.specify/extensions/agent-governance/scripts/refresh_agent_governance.py b/.specify/extensions/agent-governance/scripts/refresh_agent_governance.py
new file mode 100644
index 0000000000..fd43ca1634
--- /dev/null
+++ b/.specify/extensions/agent-governance/scripts/refresh_agent_governance.py
@@ -0,0 +1,656 @@
+#!/usr/bin/env python3
+"""Generate or refresh Spec Kit agent platform governance for the current project."""
+
+from __future__ import annotations
+
+import json
+import re
+import sys
+from pathlib import Path
+from typing import Any
+
+
+MEMORY_PATH = Path(".specify/memory/agent-governance.md")
+TEMPLATE_PATH = Path(".specify/extensions/agent-governance/templates/agent-governance-template.md")
+INTEGRATION_JSON = Path(".specify/integration.json")
+INIT_OPTIONS_JSON = Path(".specify/init-options.json")
+
+MARKER_START = "<!-- SPECKIT GOVERNANCE START -->"
+MARKER_END = "<!-- SPECKIT GOVERNANCE END -->"
+
+CONTEXT_FILES = {
+ "agy": "AGENTS.md",
+ "amp": "AGENTS.md",
+ "auggie": ".augment/rules/specify-rules.md",
+ "bob": "AGENTS.md",
+ "claude": "CLAUDE.md",
+ "codebuddy": "CODEBUDDY.md",
+ "codex": "AGENTS.md",
+ "copilot": ".github/copilot-instructions.md",
+ "cursor-agent": ".cursor/rules/specify-rules.mdc",
+ "devin": "AGENTS.md",
+ "forge": "AGENTS.md",
+ "gemini": "GEMINI.md",
+ "generic": "AGENTS.md",
+ "goose": "AGENTS.md",
+ "iflow": "IFLOW.md",
+ "junie": ".junie/AGENTS.md",
+ "kilocode": ".kilocode/rules/specify-rules.md",
+ "kimi": "KIMI.md",
+ "kiro-cli": "AGENTS.md",
+ "lingma": ".lingma/rules/specify-rules.md",
+ "opencode": "AGENTS.md",
+ "pi": "AGENTS.md",
+ "qodercli": "QODER.md",
+ "qwen": "QWEN.md",
+ "roo": ".roo/rules/specify-rules.md",
+ "shai": "SHAI.md",
+ "tabnine": "TABNINE.md",
+ "trae": ".trae/rules/project_rules.md",
+ "vibe": "AGENTS.md",
+ "windsurf": ".windsurf/rules/specify-rules.md",
+}
+
+
+def main() -> int:
+ root = Path.cwd()
+ if not (root / ".specify").is_dir():
+ print("Error: .specify/ not found. Run from a Spec Kit project root.", file=sys.stderr)
+ return 1
+
+ state = read_json(root / INTEGRATION_JSON)
+ init_options = read_json(root / INIT_OPTIONS_JSON)
+ created_memory = ensure_memory(root)
+ target = resolve_target(root, state, init_options)
+ projection = render_projection(root, target, state, created_memory)
+ evidence_summary = repository_evidence_summary(root, state, init_options) if created_memory else ""
+ action = write_projection(target, projection)
+ remove_stale_sections(root, target, init_options, state)
+
+ print(f"Target governance file: {rel(root, target)}")
+ print(f"Governance file: {action}")
+ print(f"Review target: {rel(root, target)}")
+ print(f"Internal initialization cache: {MEMORY_PATH.as_posix()} ({'created' if created_memory else 'existing'})")
+ if created_memory:
+ print(f"Repository evidence: {evidence_summary}")
+ return 0
+
+
+def ensure_memory(root: Path) -> bool:
+ memory = root / MEMORY_PATH
+ if memory.exists():
+ return False
+ template = root / TEMPLATE_PATH
+ if not template.exists():
+ raise SystemExit(f"Error: template not found: {TEMPLATE_PATH.as_posix()}")
+ memory.parent.mkdir(parents=True, exist_ok=True)
+ memory.write_text(render_initial_memory(root, template.read_text(encoding="utf-8-sig")), encoding="utf-8")
+ return True
+
+
+def render_initial_memory(root: Path, template: str) -> str:
+ content = normalize_newlines(template)
+ state = read_json(root / INTEGRATION_JSON)
+ init_options = read_json(root / INIT_OPTIONS_JSON)
+ content = replace_sync_report(content, root, state)
+ evidence = "\n".join(
+ [
+ "## Repository Evidence",
+ "",
+ *repository_evidence_lines(root, state, init_options),
+ "",
+ "## Repository Areas",
+ "",
+ *repository_area_lines(root),
+ "",
+ "## Development Commands",
+ "",
+ *development_command_lines(root),
+ "",
+ ]
+ )
+ marker = "\n## Scope\n"
+ if marker in content:
+ content = content.replace(marker, f"\n{evidence}{marker}", 1)
+ else:
+ content = content.rstrip() + "\n\n" + evidence
+ return content
+
+
+def replace_sync_report(content: str, root: Path, state: dict[str, Any]) -> str:
+ report = "\n".join(
+ [
+ "<!--",
+ "Sync Impact Report",
+ f"- Active Integration: {default_integration(state) or 'unknown'}",
+ f"- Installed Integrations: {', '.join(installed_integrations(state)) or 'none'}",
+ f"- Skills Scanned: {len(scan_skills(root))}",
+ f"- MCP Config Files Scanned: {', '.join(scan_mcp_configs(root)) or 'none'}",
+ f"- Extension Config Status: .specify/extensions.yml ({extensions_status(root)})",
+ "- Sections Changed: initialized repository evidence and development commands",
+ "- Flow: generate missing target governance files; update existing target governance files",
+ "-->",
+ ]
+ )
+ pattern = re.compile(r"<!--\nSync Impact Report\n.*?\n-->", re.DOTALL)
+ if pattern.search(content):
+ return pattern.sub(report, content, count=1)
+ return content
+
+
+def repository_evidence_summary(root: Path, state: dict[str, Any], init_options: dict[str, Any]) -> str:
+ evidence = repository_evidence_lines(root, state, init_options)
+ detected = [line for line in evidence if "none detected" not in line and "`unknown`" not in line]
+ return "; ".join(line.removeprefix("- ") for line in detected) or "none detected"
+
+
+def repository_evidence_lines(root: Path, state: dict[str, Any], init_options: dict[str, Any]) -> list[str]:
+ lines = [
+ evidence_line("README", existing_paths(root, ["README.md", "README.markdown", "README.txt"])),
+ evidence_line(
+ "Package manifest",
+ existing_paths(root, ["package.json", "pyproject.toml", "Cargo.toml", "go.mod", "Gemfile", "pom.xml", "build.gradle", "build.gradle.kts"]),
+ ),
+ evidence_line(
+ "Lockfiles",
+ existing_paths(root, ["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "uv.lock", "poetry.lock", "Cargo.lock", "go.sum", "Gemfile.lock"]),
+ ),
+ evidence_line("Task runners", existing_paths(root, ["Makefile", "Taskfile.yml", "Taskfile.yaml", "justfile"])),
+ evidence_line("CI workflows", directory_files(root, ".github/workflows")),
+ evidence_line("Source paths", existing_dirs(root, ["src", "app", "lib", "scripts", "commands", "templates"])),
+ evidence_line("Test paths", existing_dirs(root, ["test", "tests", "spec", "specs"])),
+ evidence_line("Repository areas", repository_area_paths(root)),
+ evidence_line("Existing agent context files", existing_context_files(root, init_options, state)),
+ evidence_line("Repository-local skills", scan_skills(root)),
+ evidence_line("MCP configs", scan_mcp_configs(root)),
+ f"- Active integration: `{default_integration(state) or 'unknown'}`",
+ f"- Resolved context file: `{rel(root, resolve_target(root, state, init_options))}`",
+ ]
+ return lines
+
+
+def evidence_line(label: str, values: list[str]) -> str:
+ return f"- {label}: {format_values(values)}"
+
+
+def format_values(values: list[str]) -> str:
+ return ", ".join(f"`{value}`" for value in values) if values else "none detected"
+
+
+def existing_paths(root: Path, names: list[str]) -> list[str]:
+ return [name for name in names if (root / name).is_file()]
+
+
+def existing_dirs(root: Path, names: list[str]) -> list[str]:
+ return [f"{name}/" for name in names if (root / name).is_dir()]
+
+
+def directory_files(root: Path, directory: str) -> list[str]:
+ base = root / directory
+ if not base.is_dir():
+ return []
+ return sorted(rel(root, path) for path in base.iterdir() if path.is_file())
+
+
+def repository_area_lines(root: Path) -> list[str]:
+ lines = []
+ for area in repository_area_paths(root):
+ if "/" in area.rstrip("/"):
+ parent = area.rstrip("/").split("/", 1)[0] + "/"
+ lines.append(f"- `{area}`: change with parent area `{parent}`.")
+ else:
+ lines.append(f"- `{area}`: review before changing linked areas.")
+ return lines or ["- none detected"]
+
+
+def repository_area_paths(root: Path) -> list[str]:
+ areas: list[str] = []
+ for path in sorted(root.iterdir()):
+ if not path.is_dir():
+ continue
+ areas.append(f"{path.name}/")
+ for child in sorted(path.iterdir()):
+ if child.is_dir():
+ areas.append(f"{path.name}/{child.name}/")
+ return areas
+
+
+def existing_context_files(root: Path, init_options: dict[str, Any], state: dict[str, Any]) -> list[str]:
+ paths: set[Path] = {root / "AGENTS.md"}
+ for value in CONTEXT_FILES.values():
+ target = safe_project_path(root, value)
+ if target is not None:
+ paths.add(target)
+ init_target = safe_project_path(root, init_options.get("context_file"))
+ if init_target is not None:
+ paths.add(init_target)
+ resolved = resolve_target(root, state, init_options)
+ paths.add(resolved)
+ return sorted(rel(root, path) for path in paths if path.exists())
+
+
+def development_command_lines(root: Path) -> list[str]:
+ commands = package_script_lines(root)
+ if commands:
+ commands.append("- manifest commands over ad hoc equivalents")
+ return commands
+ return ["- none detected"]
+
+
+def package_script_lines(root: Path) -> list[str]:
+ package_json = root / "package.json"
+ data = read_json(package_json)
+ scripts = data.get("scripts")
+ if not isinstance(scripts, dict):
+ return []
+ result: list[str] = []
+ for name in sorted(scripts):
+ value = scripts[name]
+ if not isinstance(value, str) or not value.strip():
+ continue
+ command = f"npm {name}" if name in {"start", "stop", "test", "restart"} else f"npm run {name}"
+ result.append(f"- `{command}` -> `{value.strip()}`")
+ return result
+
+
+def read_json(path: Path) -> dict[str, Any]:
+ if not path.exists():
+ return {}
+ try:
+ data = json.loads(path.read_text(encoding="utf-8"))
+ except (json.JSONDecodeError, OSError, UnicodeDecodeError):
+ return {}
+ return data if isinstance(data, dict) else {}
+
+
+def resolve_target(root: Path, state: dict[str, Any], init_options: dict[str, Any]) -> Path:
+ for value in (
+ init_options.get("context_file"),
+ CONTEXT_FILES.get(default_integration(state) or ""),
+ "AGENTS.md",
+ ):
+ target = safe_project_path(root, value)
+ if target is not None:
+ return target
+ return root / "AGENTS.md"
+
+
+def safe_project_path(root: Path, value: Any) -> Path | None:
+ if not isinstance(value, str) or not value.strip():
+ return None
+ raw = Path(value.strip())
+ candidate = raw if raw.is_absolute() else root / raw
+ try:
+ candidate.resolve(strict=False).relative_to(root.resolve())
+ except (OSError, ValueError):
+ return None
+ return candidate
+
+
+def default_integration(state: dict[str, Any]) -> str | None:
+ for key in ("default_integration", "integration"):
+ value = state.get(key)
+ if isinstance(value, str) and value.strip():
+ return value.strip()
+ installed = state.get("installed_integrations")
+ if isinstance(installed, list):
+ for value in installed:
+ if isinstance(value, str) and value.strip():
+ return value.strip()
+ return None
+
+
+def installed_integrations(state: dict[str, Any]) -> list[str]:
+ seen: set[str] = set()
+ values = state.get("installed_integrations")
+ if not isinstance(values, list):
+ values = []
+ default = default_integration(state)
+ ordered = ([default] if default else []) + values
+ result: list[str] = []
+ for value in ordered:
+ if not isinstance(value, str) or not value.strip():
+ continue
+ clean = value.strip()
+ if clean not in seen:
+ seen.add(clean)
+ result.append(clean)
+ return result
+
+
+def render_projection(root: Path, target: Path, state: dict[str, Any], created_memory: bool) -> str:
+ source_text, source_label = governance_source(root, target)
+ default_key = default_integration(state) or "unknown"
+ installed = installed_integrations(state)
+ style = projection_style(target)
+ lines = [
+ MARKER_START,
+ "## Repository Governance",
+ "- SSOT: this managed section.",
+ f"- Target: {rel(root, target)}",
+ f"- Active integration: {default_key}",
+ f"- Refresh source: {source_label}",
+ f"- Cache: {MEMORY_PATH.as_posix()} ({'created' if created_memory else 'present'})",
+ "",
+ "## Scope",
+ "- agent collaboration rules",
+ "- tool and MCP permissions",
+ "- write boundaries",
+ "- skill invocation contracts",
+ "- project governance: external",
+ "",
+ "## Context",
+ f"- Installed integrations: {', '.join(installed) if installed else 'none'}",
+ f"- Skills: {', '.join(scan_skills(root)) or 'none'}",
+ f"- MCP configs: {', '.join(scan_mcp_configs(root)) or 'none'}",
+ f"- Extensions config: .specify/extensions.yml ({extensions_status(root)})",
+ "",
+ "## Repository Evidence",
+ *section_or_default(source_text, ["## Repository Evidence"], repository_evidence_default()),
+ "",
+ "## Repository Areas",
+ *section_or_default(source_text, ["## Repository Areas"], repository_areas_default()),
+ "",
+ "## Directory Governance",
+ *section_or_default(source_text, ["## Directory Governance"], directory_governance_default()),
+ "",
+ "## Development Commands",
+ *section_or_default(source_text, ["## Development Commands"], development_commands_default()),
+ "",
+ "## Authority",
+ "1. Current user instruction",
+ "2. Active `SPECKIT GOVERNANCE` section",
+ "3. User-authored repository instructions for agent behavior",
+ "4. Skill-local `SKILL.md`",
+ "5. Tool and MCP defaults",
+ "",
+ "## Repository Workflow",
+ "- Read: Repository Evidence",
+ "- Run: Development Commands",
+ "- Scope: active task only",
+ "- Preserve: user-authored edits",
+ "- Protected files: implementation, CI, MCP config, secrets, permissions, tool settings",
+ "- Protected-file writes: explicit user request only",
+ "- External writes: authorized target and action only",
+ "- Handoff: changed files, commands, validation, risks",
+ "",
+ "## Write Boundaries",
+ *section_or_default(source_text, ["## Write Boundaries"], write_boundary_default(style)),
+ "",
+ "## MCP And External Tools",
+ *section_or_default(source_text, ["## MCP And External Tools", "## MCP And External Tool Policy", "## MCP Policy"], mcp_default(style)),
+ "",
+ "## Skills",
+ *section_or_default(source_text, ["## Skills", "## Skill Usage Policy", "## Skill Contract"], skill_default(style)),
+ "",
+ "## Handoff",
+ *section_or_default(source_text, ["## Handoff", "## Required Handoff Report", "## Validation"], handoff_default(style)),
+ MARKER_END,
+ "",
+ ]
+ return "\n".join(lines)
+
+
+def write_projection(target: Path, projection: str) -> str:
+ existed = target.exists()
+ existing = target.read_text(encoding="utf-8-sig") if target.exists() else ""
+ updated = upsert_section(existing, projection)
+ if target.suffix == ".mdc":
+ updated = ensure_mdc_frontmatter(updated)
+ target.parent.mkdir(parents=True, exist_ok=True)
+ target.write_text(normalize_newlines(updated), encoding="utf-8")
+ return "updated" if existed else "generated"
+
+
+def upsert_section(content: str, projection: str) -> str:
+ start = content.find(MARKER_START)
+ end = content.find(MARKER_END, start if start != -1 else 0)
+ if start != -1 and end != -1 and end > start:
+ end += len(MARKER_END)
+ if end < len(content) and content[end] == "\r":
+ end += 1
+ if end < len(content) and content[end] == "\n":
+ end += 1
+ return content[:start] + projection + content[end:]
+ if content and not content.endswith("\n"):
+ content += "\n"
+ return content + ("\n" if content else "") + projection
+
+
+def remove_stale_sections(root: Path, active: Path, init_options: dict[str, Any], state: dict[str, Any]) -> None:
+ paths = {root / "AGENTS.md"}
+ for value in CONTEXT_FILES.values():
+ target = safe_project_path(root, value)
+ if target is not None:
+ paths.add(target)
+ init_target = safe_project_path(root, init_options.get("context_file"))
+ if init_target is not None:
+ paths.add(init_target)
+ for path in paths:
+ if same_path(path, active):
+ continue
+ remove_section(path)
+
+
+def remove_section(path: Path) -> None:
+ if not path.exists():
+ return
+ content = path.read_text(encoding="utf-8-sig")
+ start = content.find(MARKER_START)
+ end = content.find(MARKER_END, start if start != -1 else 0)
+ if start == -1 or end == -1 or end <= start:
+ return
+ removal_end = end + len(MARKER_END)
+ if removal_end < len(content) and content[removal_end] == "\r":
+ removal_end += 1
+ if removal_end < len(content) and content[removal_end] == "\n":
+ removal_end += 1
+ removal_start = start
+ if removal_start > 1 and content[removal_start - 1] == "\n" and content[removal_start - 2] == "\n":
+ removal_start -= 1
+ updated = normalize_newlines(content[:removal_start] + content[removal_end:])
+ if not updated.strip() or (path.suffix == ".mdc" and re.match(r"^---\n.*?\n---\s*$", updated, re.DOTALL)):
+ path.unlink()
+ else:
+ path.write_text(updated, encoding="utf-8")
+
+
+def governance_source(root: Path, target: Path) -> tuple[str, str]:
+ managed = extract_managed_section(target)
+ if managed:
+ return managed, "active generated section"
+ memory = root / MEMORY_PATH
+ try:
+ return normalize_newlines(memory.read_text(encoding="utf-8-sig")), "initialization cache"
+ except (OSError, UnicodeDecodeError):
+ return "", "built-in defaults"
+
+
+def section_or_default(source_text: str, headings: list[str], default: list[str]) -> list[str]:
+ for heading in headings:
+ section = extract_section_from_text(source_text, heading)
+ if section:
+ return section
+ return default
+
+
+def repository_evidence_default() -> list[str]:
+ return ["- none captured"]
+
+
+def repository_areas_default() -> list[str]:
+ return ["- none detected"]
+
+
+def directory_governance_default() -> list[str]:
+ return [
+ "- Responsibility: one primary purpose per directory.",
+ "- Depth: 2.",
+ "- Coverage: include visible, hidden, generated, cache, config/env, tool, and agent directories.",
+ "- Mixed concerns: follow existing repo convention or split responsibility.",
+ "- Change impact: review linked code, tests, docs, config/env, data, assets, generated files, and tool outputs; update only when in scope and authorized.",
+ ]
+
+
+def development_commands_default() -> list[str]:
+ return ["- none recorded"]
+
+
+def extract_section(path: Path, heading: str) -> list[str]:
+ try:
+ return extract_section_from_text(path.read_text(encoding="utf-8-sig"), heading)
+ except (OSError, UnicodeDecodeError):
+ return []
+
+
+def extract_managed_section(path: Path) -> str:
+ try:
+ content = normalize_newlines(path.read_text(encoding="utf-8-sig"))
+ except (OSError, UnicodeDecodeError):
+ return ""
+ start = content.find(MARKER_START)
+ end = content.find(MARKER_END, start if start != -1 else 0)
+ if start == -1 or end == -1 or end <= start:
+ return ""
+ return content[start + len(MARKER_START) : end]
+
+
+def extract_section_from_text(text: str, heading: str) -> list[str]:
+ lines = normalize_newlines(text).splitlines()
+ capture = False
+ result: list[str] = []
+ for line in lines:
+ if line.strip() == heading:
+ capture = True
+ continue
+ if capture and line.startswith("## "):
+ break
+ if capture and line.strip():
+ result.append(line)
+ return result
+
+
+def projection_style(path: Path) -> str:
+ rel_path = path.as_posix()
+ if rel_path.endswith(".github/copilot-instructions.md"):
+ return "copilot"
+ if path.suffix == ".mdc" or "/rules/" in rel_path:
+ return "rule"
+ return "agent"
+
+
+def style_lead(style: str) -> str:
+ if style == "copilot":
+ return "Use these as concise Copilot custom instructions for this repository."
+ if style == "rule":
+ return "Apply these repository rules before planning, editing, or using tools."
+ return "Follow these repository instructions when working in this project."
+
+
+def write_boundary_default(style: str) -> list[str]:
+ if style == "rule":
+ return [
+ "- Stay inside the active task scope.",
+ "- Preserve user-authored edits.",
+ "- Preserve managed markers verbatim: `<!-- SPECKIT GOVERNANCE START -->` and `<!-- SPECKIT GOVERNANCE END -->`.",
+ ]
+ return [
+ "- Keep edits inside the active task scope and preserve user changes.",
+ "- Preserve managed markers verbatim: `<!-- SPECKIT GOVERNANCE START -->` and `<!-- SPECKIT GOVERNANCE END -->`.",
+ ]
+
+
+def mcp_default(style: str) -> list[str]:
+ return ["- Read-only unless the user authorizes mutation.", "- External writes: target, action, expected effect."]
+
+
+def skill_default(style: str) -> list[str]:
+ return [
+ "- Use active skill `SKILL.md`.",
+ "- Write scope: declared skill paths only.",
+ "- Repository-local skill specs should declare purpose, trigger, allowed read paths, allowed write paths, forbidden paths, outputs, and validation command.",
+ ]
+
+
+def handoff_default(style: str) -> list[str]:
+ return ["- changed files", "- commands run", "- validation result", "- unresolved risks"]
+
+
+def scan_feature_specs(root: Path) -> str:
+ specs = root / "specs"
+ if not specs.is_dir():
+ return "none"
+ entries = []
+ for feature in sorted(path for path in specs.iterdir() if path.is_dir()):
+ statuses = [f"{name}:{'present' if (feature / name).exists() else 'missing'}" for name in ("spec.md", "plan.md", "tasks.md")]
+ entries.append(f"{rel(root, feature)} ({', '.join(statuses)})")
+ return ", ".join(entries) if entries else "none"
+
+
+def scan_skills(root: Path) -> list[str]:
+ return sorted(rel(root, path) for path in root.rglob("SKILL.md") if not ignored(path))
+
+
+def scan_mcp_configs(root: Path) -> list[str]:
+ names = {".mcp.json", "mcp.json", "mcp.yml", "mcp.yaml", "mcp.config.json"}
+ return sorted(
+ rel(root, path)
+ for path in root.rglob("*")
+ if path.is_file() and not ignored(path) and (path.name in names or "mcp" in path.name.lower())
+ )
+
+
+def ignored(path: Path) -> bool:
+ return any(part in {".git", "__pycache__", ".venv", "node_modules"} for part in path.parts)
+
+
+def extensions_status(root: Path) -> str:
+ path = root / ".specify/extensions.yml"
+ if not path.exists():
+ return "missing"
+ return "present"
+
+
+def exists(root: Path, value: str) -> str:
+ return "present" if (root / value).exists() else "missing"
+
+
+def ensure_mdc_frontmatter(content: str) -> str:
+ stripped = content.lstrip()
+ if not stripped.startswith("---"):
+ return "---\nalwaysApply: true\n---\n\n" + content
+ match = re.match(r"^(---[ \t]*\n)(.*?)(\n---[ \t]*)(\n|$)(.*)", stripped, re.DOTALL)
+ if not match:
+ return "---\nalwaysApply: true\n---\n\n" + content
+ opening, frontmatter, closing, sep, rest = match.groups()
+ if re.search(r"(?m)^[ \t]*alwaysApply[ \t]*:[ \t]*true[ \t]*$", frontmatter):
+ return content
+ if re.search(r"(?m)^[ \t]*alwaysApply[ \t]*:", frontmatter):
+ frontmatter = re.sub(r"(?m)^([ \t]*)alwaysApply[ \t]*:.*$", r"\1alwaysApply: true", frontmatter, count=1)
+ elif frontmatter.strip():
+ frontmatter += "\nalwaysApply: true"
+ else:
+ frontmatter = "alwaysApply: true"
+ return f"{opening}{frontmatter}{closing}{sep}{rest}"
+
+
+def same_path(left: Path, right: Path) -> bool:
+ try:
+ return left.resolve(strict=False) == right.resolve(strict=False)
+ except OSError:
+ return left.absolute() == right.absolute()
+
+
+def rel(root: Path, path: Path) -> str:
+ try:
+ return path.relative_to(root).as_posix()
+ except ValueError:
+ return path.as_posix()
+
+
+def normalize_newlines(content: str) -> str:
+ return content.replace("\r\n", "\n").replace("\r", "\n")
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())

diff --git a/.specify/extensions/agent-governance/templates/agent-governance-template.md b/.specify/extensions/agent-governance/templates/agent-governance-template.md
new file mode 100644
index 0000000000..99ec0519f9
--- /dev/null
+++ b/.specify/extensions/agent-governance/templates/agent-governance-template.md
@@ -0,0 +1,53 @@
+# Agent Governance Cache
+
+<!--
+Sync Impact Report
+-->
+
+## Final Output
+
+- active agent platform governance file
+- managed `SPECKIT GOVERNANCE` section
+- cache: internal
+
+## Directory Governance
+
+- Responsibility: one primary purpose per directory.
+- Depth: 2.
+- Coverage: include visible, hidden, generated, cache, config/env, tool, and agent directories.
+- Mixed concerns: follow existing repo convention or split responsibility.
+- Change impact: review linked code, tests, docs, config/env, data, assets, generated files, and tool outputs; update only when in scope and authorized.
+
+## Scope
+
+- agent collaboration rules
+- tool and MCP permissions
+- write boundaries
+- skill invocation contracts
+- project governance: external
+
+## Write Boundaries
+
+- Scope: active task only
+- Preserve: user-authored edits
+- Preserve managed markers verbatim: `<!-- SPECKIT GOVERNANCE START -->` and `<!-- SPECKIT GOVERNANCE END -->`
+- Protected files: implementation, CI, MCP config, secrets, permissions, tool settings
+- Protected-file writes: explicit user request only
+
+## Skill Contract
+
+- Repository-local skill specs should declare purpose, trigger, allowed read paths, allowed write paths, forbidden paths, outputs, and validation command.
+
+## MCP Policy
+
+- Default: read-only
+- Mutation: explicit user intent
+- External writes: target, action, result
+- Secrets: never log, never write
+
+## Validation
+
+- changed files
+- commands run
+- tests/validation result
+- unresolved risks

diff --git a/.specify/extensions/review/scripts/bash/detect-changed-files.sh b/.specify/extensions/review/scripts/bash/detect-changed-files.sh
old mode 100644
new mode 100755

diff --git a/.specify/extensions/verify/scripts/bash/load-config.sh b/.specify/extensions/verify/scripts/bash/load-config.sh
old mode 100644
new mode 100755

diff --git a/.specify/init-options.json b/.specify/init-options.json
index 3d0c55bc7d..26d6795828 100644
--- a/.specify/init-options.json
+++ b/.specify/init-options.json
@@ -1,9 +1,9 @@
{
- "ai": "opencode",
+ "ai": "copilot",
"branch_numbering": "timestamp",
- "context_file": "AGENTS.md",
+ "context_file": ".github/copilot-instructions.md",
"here": true,
- "integration": "opencode",
+ "integration": "copilot",
"script": "sh",
"speckit_version": "0.8.8.dev0"
}
\ No newline at end of file

diff --git a/.specify/integration.json b/.specify/integration.json
index cf4062608d..d626d19afd 100644
--- a/.specify/integration.json
+++ b/.specify/integration.json
@@ -1,15 +1,15 @@
{
- "version": "0.8.8.dev0",
+ "version": "0.8.13",
"integration_state_schema": 1,
"installed_integrations": [
- "opencode"
+ "copilot"
],
"integration_settings": {
- "opencode": {
+ "copilot": {
"script": "sh",
"invoke_separator": "."
}
},
- "integration": "opencode",
- "default_integration": "opencode"
+ "integration": "copilot",
+ "default_integration": "copilot"
}

diff --git a/.specify/integrations/copilot.manifest.json b/.specify/integrations/copilot.manifest.json
index ee84b97a74..49c1cdde92 100644
--- a/.specify/integrations/copilot.manifest.json
+++ b/.specify/integrations/copilot.manifest.json
@@ -1,7 +1,7 @@
{
"integration": "copilot",
- "version": "0.8.8.dev0",
- "installed_at": "2026-05-07T18:49:21.970795+00:00",
+ "version": "0.8.13",
+ "installed_at": "2026-05-21T18:50:11.969212+00:00",
"files": {
".github/agents/speckit.analyze.agent.md": "699032fdd49afe31d23c7191f3fe7bcb1d14b081fbc94c2287e6ba3a57574fda",
".github/agents/speckit.checklist.agent.md": "d7d691689fe45427c868dcf18ade4df500f0c742a6c91923fefba405d6466dde",

diff --git a/.specify/integrations/opencode.manifest.json b/.specify/integrations/opencode.manifest.json
deleted file mode 100644
index e8f9996682..0000000000
--- a/.specify/integrations/opencode.manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "integration": "opencode",
- "version": "0.8.8.dev0",
- "installed_at": "2026-05-07T18:50:21.381460+00:00",
- "files": {
- ".opencode/command/speckit.analyze.md": "699032fdd49afe31d23c7191f3fe7bcb1d14b081fbc94c2287e6ba3a57574fda",
- ".opencode/command/speckit.checklist.md": "d7d691689fe45427c868dcf18ade4df500f0c742a6c91923fefba405d6466dde",
- ".opencode/command/speckit.clarify.md": "0cc766dcc5cab233ccdf3bc4cfb5759a6d7d1e13e29f611083046f818f5812bb",
- ".opencode/command/speckit.constitution.md": "58d35eb026f56bb7364d91b8b0382d5dd1249ded6c1449a2b69546693afb85f7",
- ".opencode/command/speckit.implement.md": "2acb475f761e5b65319c4e71847bd07b88c933b45da7be45e7801271f64fcd4d",
- ".opencode/command/speckit.plan.md": "5b1e9c9b5a26a1877fe3b655a9350562cf5ee88788f9030e6b8a9dc1de88b347",
- ".opencode/command/speckit.specify.md": "c7b1ab7ceafc42607e86dd6c0dab0b5cb74462a93a3cdd3b5e7173468cc88bdf",
- ".opencode/command/speckit.tasks.md": "6b42e295fb67082392b4b62febf297c73655ea67cc9379cd5df80468e920cb4c",
- ".opencode/command/speckit.taskstoissues.md": "e84794f7a839126defb364ca815352c5c2b2d20db2d6da399fa53e4ddbb7b3ee"
- }
-}

diff --git a/.specify/integrations/speckit.manifest.json b/.specify/integrations/speckit.manifest.json
index 7908f079c2..c2358b8880 100644
--- a/.specify/integrations/speckit.manifest.json
+++ b/.specify/integrations/speckit.manifest.json
@@ -1,6 +1,6 @@
{
"integration": "speckit",
- "version": "0.8.8.dev0",
+ "version": "0.8.13",
"installed_at": "2026-05-07T18:46:46.194118+00:00",
"files": {
".specify/scripts/bash/common.sh": "dd638316259e699fd466542c77ef16af5eb198efe0447c081f86b890db414ba8",
@@ -10,8 +10,8 @@
".specify/scripts/bash/create-new-feature.sh": "bcf4964ca0c6c78717bb42d9e66b8c7e5ee82779cd96afc5aa7b08b75abe5790",
".specify/templates/constitution-template.md": "ce7549540fa45543cca797a150201d868e64495fdff39dc38246fb17bd4024b3",
".specify/templates/checklist-template.md": "312eee8291dfa984b21f95ddd0ca778e7a1f0b3a64bfc470d79762a3e3f5d7b8",
- ".specify/templates/tasks-template.md": "5da92ac1fbf5be2f9018a5064497995bf3592761ccb6b3951503c63d851297e8",
- ".specify/templates/spec-template.md": "785dc50d856dd92d6515eca0761e16dce0c9ba0a3cd07154fd33eae77932422a",
- ".specify/templates/plan-template.md": "873e84b226fe3d24afe28046931b20db9bbb9210366428dc958a515349ed6e68"
+ ".specify/templates/tasks-template.md": "c731575d8099b3f871861186fbd1a592b51b2ba57fb99e1a0dab439ff6d5608f",
+ ".specify/templates/spec-template.md": "3945437fc35cd30a5b2bf7beea680337c3516826d3efa5a6b92c4a7eca1ba28e",
+ ".specify/templates/plan-template.md": "3fdc12da2eb157def636948c157bfb638b265e70b2e3246a0e09c8d5db710e91"
}
}

diff --git a/.specify/memory/agent-governance.md b/.specify/memory/agent-governance.md
new file mode 100644
index 0000000000..c1a8e45ba2
--- /dev/null
+++ b/.specify/memory/agent-governance.md
@@ -0,0 +1,84 @@
+# Agent Governance Cache
+
+<!--
+Sync Impact Report
+-->
+
+## Final Output
+
+- active agent platform governance file
+- managed `SPECKIT GOVERNANCE` section
+- cache: internal
+
+## Directory Governance
+
+- Responsibility: one primary purpose per directory.
+- Depth: 2.
+- Coverage: include visible, hidden, generated, cache, config/env, tool, and agent directories.
+- Mixed concerns: follow existing repo convention or split responsibility.
+- Change impact: review linked code, tests, docs, config/env, data, assets, generated files, and tool outputs; update only when in scope and authorized.
+
+## Repository Evidence
+
+- README: `README.md`
+- Package manifest: `Gemfile`, `build.gradle.kts`
+- Lockfiles: `Gemfile.lock`
+- Task runners: none detected
+- CI workflows: `.github/workflows/create-or-promote-release.yml`, `.github/workflows/dependency-submission.yml`, `.github/workflows/docs-deploy.yml`, `.github/workflows/docs-governance.yml`, `.github/workflows/docs-release.yml`, `.github/workflows/main-check.yml`, `.github/workflows/merge-queue.yml`, `.github/workflows/models_issue_triage.yml`, `.github/workflows/models_pr_triage.yml`, `.github/workflows/moderate.yml`, `.github/workflows/post-release-cleanup.yml`, `.github/workflows/pr_enforce_labels.yml`, `.github/workflows/promote.yml`, `.github/workflows/publish-core.yml`, `.github/workflows/pull-request-target.yml`, `.github/workflows/pull-request.yml`, `.github/workflows/release.yml`, `.github/workflows/reusable-check.yml`, `.github/workflows/scheduled-updates.yml`, `.github/workflows/stale.yml`, `.github/workflows/sync-android-docs.yml`, `.github/workflows/update-changelog.yml`
+- Source paths: `app/`, `scripts/`
+- Test paths: `specs/`
+- Repository areas: (see "Repository Areas" section below for top-level listing)
+- Existing agent context files: `.github/copilot-instructions.md`, `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`
+- Repository-local skills: `.agent_refs/mqttastic-client-kmp/.github/skills/mqtt-kmp/SKILL.md`, `.skills/ci-cost-control/SKILL.md`, `.skills/code-review/SKILL.md`, `.skills/compose-ui/SKILL.md`, `.skills/design-standards/SKILL.md`, `.skills/implement-feature/SKILL.md`, `.skills/kmp-architecture/SKILL.md`, `.skills/navigation-and-di/SKILL.md`, `.skills/new-branch/SKILL.md`, `.skills/project-overview/SKILL.md`, `.skills/speckit/SKILL.md`, `.skills/testing-ci/SKILL.md`
+- MCP configs: `.agent_refs/firmware/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp`, `.agent_refs/firmware/src/modules/Telemetry/Sensor/MCP9808Sensor.h`, `androidApp/build/intermediates/incremental/googleDebug-mergeJavaRes/zip-cache/ut0r9CiGRq6mCprTK2blRg==`, `app/build/intermediates/incremental/fdroidDebug-mergeJavaRes/zip-cache/mcpnRT6ZHkD92YpTv5y52w==`, `app/build/intermediates/incremental/googleDebug-mergeJavaRes/zip-cache/mcpnRT6ZHkD92YpTv5y52w==`, `app/build/intermediates/incremental/googleDebug-mergeJavaRes/zip-cache/ut0r9CiGRq6mCprTK2blRg==`
+- Active integration: `copilot`
+- Resolved context file: `AGENTS.md`
+
+## Repository Areas
+
+**Policy**: Subdirectories inherit parent area governance rules. When modifying a subdirectory,
+review the parent area's context for impact. Top-level directories require review before
+changing linked areas; child directories change with their parent.
+
+**Top-level areas requiring review**: `.agent_memory/`, `.agent_plans/`, `.agent_refs/`,
+`.github/`, `.specify/`, `androidApp/`, `app/`, `build-logic/`, `config/`, `core/`,
+`desktop/`, `desktopApp/`, `docs/`, `docs-site/`, `fastlane/`, `feature/`, `gradle/`,
+`ios/`, `iosApp/`, `offline-repository/`, `screenshot-tests/`, `scripts/`, `specs/`
+
+## Development Commands
+
+- none detected
+
+## Scope
+
+- agent collaboration rules
+- tool and MCP permissions
+- write boundaries
+- skill invocation contracts
+- project governance: external
+
+## Write Boundaries
+
+- Scope: active task only
+- Preserve: user-authored edits
+- Preserve managed markers verbatim: `<!-- SPECKIT GOVERNANCE START -->` and `<!-- SPECKIT GOVERNANCE END -->`
+- Protected files: implementation, CI, MCP config, secrets, permissions, tool settings
+- Protected-file writes: explicit user request only
+
+## Skill Contract
+
+- Repository-local skill specs should declare purpose, trigger, allowed read paths, allowed write paths, forbidden paths, outputs, and validation command.
+
+## MCP Policy
+
+- Default: read-only
+- Mutation: explicit user intent
+- External writes: target, action, result
+- Secrets: never log, never write
+
+## Validation
+
+- changed files
+- commands run
+- tests/validation result
+- unresolved risks

diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md
index e7b45102cf..56648f6d6a 100644
--- a/.specify/memory/constitution.md
+++ b/.specify/memory/constitution.md
@@ -1,17 +1,14 @@
<!--
SYNC IMPACT REPORT
==================
-Version change: 1.2.0 → 1.3.0
+Version change: 1.3.1 → 1.3.2
Modified principles:
- - VI. Verify Before Push → renumbered to VII.
-Added sections:
- - VI. Documentation Freshness (new principle requiring last_updated frontmatter,
- blocking staleness check, link validation, coverage checks, freshness warnings)
+ - I–VII: Rationale blocks compressed into HTML comments (no semantic change)
+Modified sections: None.
+Added sections: None.
Removed sections: None.
-Templates requiring updates:
- - .specify/templates/checklist-template.md — Add CHK006 for documentation freshness
- - .specify/templates/plan-template.md — Constitution Check VII for docs freshness
-Follow-up TODOs: Update AGENTS.md with docs governance reference.
+Templates requiring updates: None (no principle renumbering).
+Follow-up TODOs: None.
-->
# Meshtastic Android (KMP) Constitution
@@ -28,9 +25,7 @@ MUST be used in place of JVM/Android-specific APIs:
- MUST NOT import `java.*` or `android.*` in any `commonMain` module.
- Platform-specific implementations belong in `androidMain`/`desktopMain` actual
declarations only.
-- Rationale: The project goal is multi-platform parity (Android, Desktop, iOS). Framework
- bleed in `commonMain` breaks compilability on non-Android targets and undermines the
- entire decoupling effort.
+<!-- Rationale: Multi-platform parity (Android, Desktop, iOS). Framework bleed in commonMain breaks compilability on non-Android targets. -->
### II. Zero Lint Tolerance
@@ -39,8 +34,7 @@ All code contributions MUST pass static analysis before merge:
- `./gradlew spotlessApply` MUST be run and `spotlessCheck` MUST pass with no violations.
- `detekt` MUST pass with no new violations introduced.
- A task or PR is considered incomplete if either check fails.
-- Rationale: Consistent code style and static analysis gates prevent technical debt
- accumulation and catch bugs that tests alone miss.
+<!-- Rationale: Consistent code style and static analysis gates prevent technical debt accumulation. -->
### III. Compose Multiplatform UI
@@ -51,8 +45,7 @@ All UI MUST use JetBrains Compose Multiplatform, not Android-only Jetpack Compos
- Floats MUST be pre-formatted using `NumberFormatter.format()` before display in any
composable.
- UI MUST compile and render correctly on all supported targets (Android, Compose Desktop).
-- Rationale: Compose Multiplatform ensures UI consistency across platforms and enforces the
- project's multi-platform architecture goal.
+<!-- Rationale: Compose Multiplatform ensures UI consistency across platforms. -->
### IV. Privacy First
@@ -65,8 +58,7 @@ times:
circumstances.
- `core/proto` is a read-only upstream submodule (`meshtastic/protobufs`). MUST NOT modify
`.proto` files directly; proto changes require an upstream issue labeled `upstream`.
-- Rationale: Meshtastic users rely on the mesh for private, off-grid communications. Data
- leaks could endanger users in sensitive or adversarial deployments.
+<!-- Rationale: Meshtastic users rely on the mesh for private, off-grid communications. Data leaks could endanger users in sensitive deployments. -->
### V. Design Standards Compliance
@@ -74,8 +66,8 @@ All user-facing UI MUST conform to the Meshtastic Client Design Standards:
- The canonical reference lives at:
`https://raw.githubusercontent.com/meshtastic/design/refs/heads/master/standards/meshtastic_design_standards_latest.md`
-- New screens and significant UI changes MUST be reviewed against the design standards
- before merge.
+- New screens and significant UI changes (any screen with ≥3 composables or a new
+ navigation destination) MUST be reviewed against the design standards before merge.
- Deviations from the design standards require explicit justification in the PR description
with a rationale for why the standard cannot or should not be followed.
- Features that affect multiple platforms (messaging, settings, telemetry, etc.) MUST
@@ -84,9 +76,7 @@ All user-facing UI MUST conform to the Meshtastic Client Design Standards:
or create one using the `TEMPLATE.md` in that directory before writing the
Android implementation spec. Platform-specific-only features (e.g., Android widget,
Wear OS tile) may mark the `Cross-Platform Spec` field as N/A with justification.
-- Rationale: Consistent cross-platform UX across Android, iOS, and other clients ensures
- users have a predictable experience regardless of platform. The design standards are
- maintained collaboratively across all Meshtastic client teams.
+<!-- Rationale: Consistent cross-platform UX ensures users have a predictable experience regardless of platform. -->
### VI. Documentation Freshness
@@ -118,9 +108,7 @@ Governance rules:
- Image references MUST use root-relative paths (`/assets/screenshots/filename.png`) so
they resolve correctly in both Jekyll and the in-app renderer. The sync script rewrites
these to Docusaurus paths automatically.
-- Rationale: Documentation that drifts from the implementation misleads users, increases
- support burden, and undermines the in-app help experience. Three distinct consumers
- means a single source change must be verified across all delivery channels.
+<!-- Rationale: Documentation drift misleads users and increases support burden. Three distinct consumers means changes must be verified across all delivery channels. -->
### VII. Verify Before Push
@@ -131,26 +119,15 @@ Local verification MUST complete successfully before any `git push`:
- After pushing, CI status MUST be confirmed via `gh pr checks <PR>` or
`gh run list --branch <branch> --limit 5`. Phrases like "CI should be green" are
explicitly prohibited.
-- Rationale: CI has failed repeatedly due to skipped local checks. Verification is a hard
- gate, not an optimistic assumption.
+<!-- Rationale: Verification is a hard gate, not an optimistic assumption. Skipped local checks are the leading cause of CI failures. -->
## Development Workflow
-The following workflow steps are non-negotiable for all contributors and agents:
-
-- **Bootstrap First**: The mandatory bootstrap steps in `.skills/project-overview/SKILL.md`
- MUST be executed before any build operation in a new session.
-- **Baseline Verification**: Before any PR is opened or pushed, run:
- `./gradlew spotlessApply spotlessCheck detekt assembleDebug test allTests`
-- **String Resources**: After adding any string resource, run
- `python3 scripts/sort-strings.py` to maintain alphabetical organization and regenerate
- `strings-index.txt`. Consult `strings-index.txt` before reading large string files.
-- **Memory Persistence**: `.agent_memory/session_context.md` MUST be updated at the end of
- every agent session or major task to preserve context across sessions.
-- **Plan Before Execution**: Complex refactors MUST have a plan written in `.agent_plans/`
- (git-ignored) before execution begins.
-- **Context Discipline**: Agents MUST NOT read binary files (PNG, MP3, etc.) or vacuum the
- entire codebase for localized fixes. Limit context reads to relevant modules.
+Non-negotiable workflow steps are defined in `AGENTS.md` `<process_essentials>`. Key
+requirements: bootstrap before build, baseline verification before push, sort-strings after
+adding resources, update `.agent_memory/session_context.md` per session, plan complex
+refactors (touching ≥3 modules or >200 LOC changed) in `.agent_plans/`, limit context
+reads to relevant modules.
## Architecture Constraints
@@ -170,12 +147,27 @@ The following module boundaries and technology choices are fixed for this projec
- **Language & Toolchain**: Kotlin 2.3+ targeting JDK 21. Java source files MUST NOT be
introduced in KMP modules.
+## Operational Standards
+
+The following coding standards are enforced by contextual instruction files
+(`.github/instructions/`) scoped to relevant source sets. They are acknowledged by this
+constitution but defined and maintained in their respective files:
+
+- `safeCatching {}` over `runCatching {}` in coroutine/suspend contexts
+- `org.meshtastic.core.common.util.ioDispatcher` over `Dispatchers.IO`
+- `MeshtasticIcons` (from `core/ui/icon/`) over `material.icons.Icons`
+- `MetricFormatter` for display strings (temperature, voltage, percent, signal)
+- `stringResource(Res.string.key)` with `python3 scripts/sort-strings.py` after additions
+- `kotlinx.coroutines.CancellationException` (not `kotlin.coroutines.cancellation.*`)
+- Branch naming: `feat/`, `fix/`, `chore/`, `docs/`, `build/`, `ci/`, `refactor/`,
+ `test/`, `deps/`, or numeric spec prefix; always off `origin/main`
+
## Governance
-This constitution supersedes all other practices, coding guidelines, and agent instructions.
-`AGENTS.md` is the authoritative source of truth. The files
-`.github/copilot-instructions.md`, `CLAUDE.md`, and `GEMINI.md` MUST redirect to
-`AGENTS.md` and MUST NOT diverge from it.
+This constitution is the canonical governance document and supersedes all other practices,
+coding guidelines, and agent instructions. `AGENTS.md` is the agent-facing operational
+summary derived from this constitution. The files `.github/copilot-instructions.md`,
+`CLAUDE.md`, and `GEMINI.md` MUST redirect to `AGENTS.md` and MUST NOT diverge from it.
**Amendment Procedure**:
1. Propose the amendment with rationale and a migration plan in a PR description.
@@ -197,4 +189,4 @@ This constitution supersedes all other practices, coding guidelines, and agent i
Constitution Check confirming all seven principles were evaluated. Complexity violations
require explicit justification in the Complexity Tracking table of the plan document.
-**Version**: 1.3.0 | **Ratified**: 2026-05-07 | **Last Amended**: 2026-05-13
+**Version**: 1.3.2 | **Ratified**: 2026-05-07 | **Last Amended**: 2026-05-21

diff --git a/.specify/presets/.cache/catalog-ff86b51b80a289e5-metadata.json b/.specify/presets/.cache/catalog-ff86b51b80a289e5-metadata.json
new file mode 100644
index 0000000000..ccb652a974
--- /dev/null
+++ b/.specify/presets/.cache/catalog-ff86b51b80a289e5-metadata.json
@@ -0,0 +1,4 @@
+{
+ "cached_at": "2026-05-21T18:52:11.605092+00:00",
+ "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.community.json"
+}
\ No newline at end of file

diff --git a/.specify/presets/.cache/catalog-ff86b51b80a289e5.json b/.specify/presets/.cache/catalog-ff86b51b80a289e5.json
new file mode 100644
index 0000000000..1e044bf1fe
--- /dev/null
+++ b/.specify/presets/.cache/catalog-ff86b51b80a289e5.json
@@ -0,0 +1,577 @@
+{
+ "schema_version": "1.0",
+ "updated_at": "2026-05-05T10:00:00Z",
+ "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.community.json",
+ "presets": {
+ "a11y-governance": {
+ "name": "A11Y Governance",
+ "id": "a11y-governance",
+ "version": "0.2.0",
+ "description": "Adds accessibility, bilingual DE/EN delivery, CEFR-B2 readability, and inclusive-content governance to Spec Kit.",
+ "author": "Thorsten Hindermann",
+ "repository": "https://github.com/hindermath/spec-kit-preset-a11y-governance",
+ "download_url": "https://github.com/hindermath/spec-kit-preset-a11y-governance/archive/refs/tags/v0.2.0.zip",
+ "homepage": "https://github.com/hindermath/spec-kit-preset-a11y-governance",
+ "documentation": "https://github.com/hindermath/spec-kit-preset-a11y-governance/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.8.0"
+ },
+ "provides": {
+ "templates": 9,
+ "commands": 3
+ },
+ "tags": [
+ "a11y",
+ "accessibility",
+ "bilingual",
+ "wcag",
+ "inclusion"
+ ],
+ "created_at": "2026-04-27T00:00:00Z",
+ "updated_at": "2026-04-27T00:00:00Z"
+ },
+ "agent-parity-governance": {
+ "name": "Agent Parity Governance",
+ "id": "agent-parity-governance",
+ "version": "0.1.0",
+ "description": "Keeps shared AI-agent guidance aligned across a project-defined set of agent instruction surfaces.",
+ "author": "Thorsten Hindermann",
+ "repository": "https://github.com/hindermath/spec-kit-preset-agent-parity-governance",
+ "download_url": "https://github.com/hindermath/spec-kit-preset-agent-parity-governance/archive/refs/tags/v0.1.0.zip",
+ "homepage": "https://github.com/hindermath/spec-kit-preset-agent-parity-governance",
+ "documentation": "https://github.com/hindermath/spec-kit-preset-agent-parity-governance/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.8.0"
+ },
+ "provides": {
+ "templates": 6,
+ "commands": 3
+ },
+ "tags": [
+ "agents",
+ "governance",
+ "parity",
+ "agent-guidance",
+ "multi-agent"
+ ],
+ "created_at": "2026-04-27T00:00:00Z",
+ "updated_at": "2026-04-27T00:00:00Z"
+ },
+ "aide-in-place": {
+ "name": "AIDE In-Place Migration",
+ "id": "aide-in-place",
+ "version": "1.0.0",
+ "description": "Adapts the AIDE workflow for in-place technology migrations (X \u2192 Y pattern). Overrides vision, roadmap, progress, and work item commands with migration-specific guidance.",
+ "author": "mnriem",
+ "repository": "https://github.com/mnriem/spec-kit-presets",
+ "download_url": "https://github.com/mnriem/spec-kit-presets/releases/download/aide-in-place-v1.0.0/aide-in-place.zip",
+ "homepage": "https://github.com/mnriem/spec-kit-presets",
+ "documentation": "https://github.com/mnriem/spec-kit-presets/blob/main/aide-in-place/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.2.0",
+ "extensions": [
+ "aide"
+ ]
+ },
+ "provides": {
+ "templates": 2,
+ "commands": 8
+ },
+ "tags": [
+ "migration",
+ "in-place",
+ "brownfield",
+ "aide"
+ ]
+ },
+ "architecture-governance": {
+ "name": "Architecture Governance",
+ "id": "architecture-governance",
+ "version": "0.2.0",
+ "description": "Adds secure architecture governance, threat modeling, STRIDE/CAPEC, Zero Trust, S-ADRs, and OWASP SAMM to Spec Kit.",
+ "author": "Thorsten Hindermann",
+ "repository": "https://github.com/hindermath/spec-kit-preset-architecture-governance",
+ "download_url": "https://github.com/hindermath/spec-kit-preset-architecture-governance/archive/refs/tags/v0.2.0.zip",
+ "homepage": "https://github.com/hindermath/spec-kit-preset-architecture-governance",
+ "documentation": "https://github.com/hindermath/spec-kit-preset-architecture-governance/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.8.0"
+ },
+ "provides": {
+ "templates": 11,
+ "commands": 3
+ },
+ "tags": [
+ "architecture",
+ "governance",
+ "threat-modeling",
+ "stride",
+ "zero-trust"
+ ],
+ "created_at": "2026-04-27T00:00:00Z",
+ "updated_at": "2026-04-27T00:00:00Z"
+ },
+ "canon-core": {
+ "name": "Canon Core",
+ "id": "canon-core",
+ "version": "0.1.0",
+ "description": "Adapts original Spec Kit workflow to work together with Canon extension.",
+ "author": "Maxim Stupakov",
+ "download_url": "https://github.com/maximiliamus/spec-kit-canon/releases/download/v0.1.0/spec-kit-canon-core-v0.1.0.zip",
+ "repository": "https://github.com/maximiliamus/spec-kit-canon",
+ "homepage": "https://github.com/maximiliamus/spec-kit-canon",
+ "documentation": "https://github.com/maximiliamus/spec-kit-canon/blob/master/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.4.3"
+ },
+ "provides": {
+ "templates": 2,
+ "commands": 8
+ },
+ "tags": [
+ "baseline",
+ "canon",
+ "spec-first"
+ ]
+ },
+ "claude-ask-questions": {
+ "name": "Claude AskUserQuestion",
+ "id": "claude-ask-questions",
+ "version": "1.0.0",
+ "description": "Upgrades /speckit.clarify and /speckit.checklist on Claude Code from Markdown-table prompts to the native AskUserQuestion picker, with a recommended option and reasoning on every question.",
+ "author": "0xrafasec",
+ "repository": "https://github.com/0xrafasec/spec-kit-preset-claude-ask-questions",
+ "download_url": "https://github.com/0xrafasec/spec-kit-preset-claude-ask-questions/archive/refs/tags/v1.0.0.zip",
+ "homepage": "https://github.com/0xrafasec/spec-kit-preset-claude-ask-questions",
+ "documentation": "https://github.com/0xrafasec/spec-kit-preset-claude-ask-questions/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.6.0"
+ },
+ "provides": {
+ "templates": 0,
+ "commands": 2
+ },
+ "tags": [
+ "claude",
+ "ask-user-question",
+ "clarify",
+ "checklist"
+ ],
+ "created_at": "2026-04-13T00:00:00Z",
+ "updated_at": "2026-04-13T00:00:00Z"
+ },
+ "cross-platform-governance": {
+ "name": "Cross-Platform Governance",
+ "id": "cross-platform-governance",
+ "version": "0.1.0",
+ "description": "Adds Bash and PowerShell parity, dry-run/WhatIf parity, man-page expectations, and Verb-Noun Cmdlet discipline.",
+ "author": "Thorsten Hindermann",
+ "repository": "https://github.com/hindermath/spec-kit-preset-cross-platform-governance",
+ "download_url": "https://github.com/hindermath/spec-kit-preset-cross-platform-governance/archive/refs/tags/v0.1.0.zip",
+ "homepage": "https://github.com/hindermath/spec-kit-preset-cross-platform-governance",
+ "documentation": "https://github.com/hindermath/spec-kit-preset-cross-platform-governance/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.8.0"
+ },
+ "provides": {
+ "templates": 8,
+ "commands": 3
+ },
+ "tags": [
+ "cross-platform",
+ "bash",
+ "powershell",
+ "man-page",
+ "cmdlet"
+ ],
+ "created_at": "2026-04-27T00:00:00Z",
+ "updated_at": "2026-04-27T00:00:00Z"
+ },
+ "explicit-task-dependencies": {
+ "name": "Explicit Task Dependencies",
+ "id": "explicit-task-dependencies",
+ "version": "1.0.0",
+ "description": "Adds explicit (depends on T###) dependency declarations and an Execution Wave DAG to tasks.md for dependency-resolved parallel scheduling",
+ "author": "Quratulain-bilal",
+ "repository": "https://github.com/Quratulain-bilal/spec-kit-preset-explicit-task-dependencies",
+ "download_url": "https://github.com/Quratulain-bilal/spec-kit-preset-explicit-task-dependencies/archive/refs/tags/v1.0.0.zip",
+ "homepage": "https://github.com/Quratulain-bilal/spec-kit-preset-explicit-task-dependencies",
+ "documentation": "https://github.com/Quratulain-bilal/spec-kit-preset-explicit-task-dependencies/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.4.0"
+ },
+ "provides": {
+ "templates": 1,
+ "commands": 1
+ },
+ "tags": [
+ "dependencies",
+ "parallel",
+ "scheduling",
+ "wave-dag"
+ ]
+ },
+ "fiction-book-writing": {
+ "name": "Fiction Book Writing",
+ "id": "fiction-book-writing",
+ "version": "1.7.0",
+ "description": "Spec-Driven Development for novel and long-form fiction. 27 AI commands from idea to submission: story bible governance, 9 POV modes, all major plot structure frameworks, scene-by-scene drafting with quality gates, audiobook pipeline (SSML/ElevenLabs), cover design, sensitivity review, pacing and prose statistics, and pandoc-based export to DOCX/EPUB/LaTeX. Two style modes: author voice sample extraction or humanized-AI prose with 5 craft profiles. 12 languages supported. Support for offline semantic search.",
+ "author": "Andreas Daumann",
+ "repository": "https://github.com/adaumann/speckit-preset-fiction-book-writing",
+ "download_url": "https://github.com/adaumann/speckit-preset-fiction-book-writing/archive/refs/tags/v1.7.0.zip",
+ "homepage": "https://github.com/adaumann/speckit-preset-fiction-book-writing",
+ "documentation": "https://github.com/adaumann/speckit-preset-fiction-book-writing/blob/main/fiction-book-writing/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.5.0"
+ },
+ "provides": {
+ "templates": 22,
+ "commands": 27,
+ "scripts": 2
+ },
+ "tags": [
+ "writing",
+ "novel",
+ "fiction",
+ "storytelling",
+ "creative-writing",
+ "kdp",
+ "multi-pov",
+ "export",
+ "book",
+ "brainstorming",
+ "roleplay",
+ "audiobook",
+ "language-support"
+ ],
+ "created_at": "2026-04-09T08:00:00Z",
+ "updated_at": "2026-04-27T08:00:00Z"
+ },
+ "game-narrative-writing": {
+ "name": "Game Narrative Writing",
+ "id": "game-narrative-writing",
+ "version": "1.0.0",
+ "description": "Spec-Driven Development for interactive game-narrative pre-production in video games. Authors write in a portable generic format, Twine/Sugarcube (.twee) or Ink (.ink). Covers choice-IF, visual novels, and branching dialogue. Supports Tier 1 mechanic hooks (flag, counter, inventory, timer, trust, currency, npc_state, ending_condition), multi-ending design, series carry-over variable registry, and NPC-focused character architecture.",
+ "author": "Andreas Daumann",
+ "repository": "https://github.com/adaumann/speckit-preset-game-narrative-writing",
+ "download_url": "https://github.com/adaumann/speckit-preset-game-narrative-writing/archive/refs/tags/v1.0.0.zip",
+ "homepage": "https://github.com/adaumann/speckit-preset-game-narrative-writing",
+ "documentation": "https://github.com/adaumann/speckit-preset-game-narrative-writing/blob/main/game-narrative-writing/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.5.0"
+ },
+ "provides": {
+ "templates": 22,
+ "commands": 36,
+ "scripts": 2
+ },
+ "tags": [
+ "game-writing",
+ "interactive-fiction",
+ "twine",
+ "ink",
+ "renpy",
+ "point-and-click",
+ "branching-narrative",
+ "choice-if",
+ "visual-novel",
+ "mechanic-hooks",
+ "game-narrative",
+ "export",
+ "series"
+ ],
+ "created_at": "2026-05-05T08:00:00Z",
+ "updated_at": "2026-05-05T08:00:00Z"
+ },
+ "isaqb-architecture-governance": {
+ "name": "iSAQB Architecture Governance",
+ "id": "isaqb-architecture-governance",
+ "version": "0.1.0",
+ "description": "Adds general iSAQB/CPSA-F and arc42 architecture governance, including views, quality scenarios, ADRs, risks, and technical debt.",
+ "author": "Thorsten Hindermann",
+ "repository": "https://github.com/hindermath/spec-kit-preset-isaqb-architecture-governance",
+ "download_url": "https://github.com/hindermath/spec-kit-preset-isaqb-architecture-governance/archive/refs/tags/v0.1.0.zip",
+ "homepage": "https://github.com/hindermath/spec-kit-preset-isaqb-architecture-governance",
+ "documentation": "https://github.com/hindermath/spec-kit-preset-isaqb-architecture-governance/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.8.0"
+ },
+ "provides": {
+ "templates": 13,
+ "commands": 3
+ },
+ "tags": [
+ "architecture",
+ "governance",
+ "isaqb",
+ "arc42",
+ "adr"
+ ],
+ "created_at": "2026-04-27T00:00:00Z",
+ "updated_at": "2026-04-27T00:00:00Z"
+ },
+ "jira": {
+ "name": "Jira Issue Tracking",
+ "id": "jira",
+ "version": "1.0.0",
+ "description": "Overrides speckit.taskstoissues to create Jira epics, stories, and tasks instead of GitHub Issues via Atlassian MCP tools.",
+ "author": "luno",
+ "repository": "https://github.com/luno/spec-kit-preset-jira",
+ "download_url": "https://github.com/luno/spec-kit-preset-jira/archive/refs/tags/v1.0.0.zip",
+ "homepage": "https://github.com/luno/spec-kit-preset-jira",
+ "documentation": "https://github.com/luno/spec-kit-preset-jira/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.1.0"
+ },
+ "provides": {
+ "templates": 0,
+ "commands": 1
+ },
+ "tags": [
+ "jira",
+ "atlassian",
+ "issue-tracking",
+ "preset"
+ ],
+ "created_at": "2026-04-15T00:00:00Z",
+ "updated_at": "2026-04-15T00:00:00Z"
+ },
+ "mde": {
+ "name": "Model Driven Engineering",
+ "id": "mde",
+ "version": "0.5.1",
+ "description": "Focuses on streamlined commands, app repository support, cross-spec support, and capability-aware project memory for model-driven engineering workflows.",
+ "author": "Ralph Hanna",
+ "repository": "https://github.com/AI-MDE/spec-kit-preset-mde",
+ "download_url": "https://github.com/AI-MDE/spec-kit-preset-mde/archive/refs/tags/v0.5.1.zip",
+ "homepage": "https://github.com/AI-MDE/spec-kit-preset-mde",
+ "documentation": "https://github.com/AI-MDE/spec-kit-preset-mde/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.1.0",
+ "extensions": [
+ "mde"
+ ]
+ },
+ "provides": {
+ "templates": 6,
+ "commands": 11
+ },
+ "tags": [
+ "model-driven-engineering",
+ "software-lifecycle",
+ "business-analysis",
+ "business-application",
+ "multi-layered-architecture"
+ ],
+ "created_at": "2026-05-08T00:00:00Z",
+ "updated_at": "2026-05-08T00:00:00Z"
+ },
+ "multi-repo-branching": {
+ "name": "Multi-Repo Branching",
+ "id": "multi-repo-branching",
+ "version": "1.0.0",
+ "description": "Coordinates feature branch creation across multiple git repositories (independent repos and submodules) during plan and tasks phases.",
+ "author": "sakitA",
+ "repository": "https://github.com/sakitA/spec-kit-preset-multi-repo-branching",
+ "download_url": "https://github.com/sakitA/spec-kit-preset-multi-repo-branching/archive/refs/tags/v1.0.0.zip",
+ "homepage": "https://github.com/sakitA/spec-kit-preset-multi-repo-branching",
+ "documentation": "https://github.com/sakitA/spec-kit-preset-multi-repo-branching/blob/master/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.4.0"
+ },
+ "provides": {
+ "templates": 0,
+ "commands": 2
+ },
+ "tags": [
+ "multi-repo-branching",
+ "multi-module",
+ "submodules",
+ "monorepo"
+ ],
+ "created_at": "2026-04-09T00:00:00Z",
+ "updated_at": "2026-04-09T00:00:00Z"
+ },
+ "pirate": {
+ "name": "Pirate Speak (Full)",
+ "id": "pirate",
+ "version": "1.0.0",
+ "description": "Arrr! Transforms all Spec Kit output into pirate speak. Specs, plans, and tasks be written fer scallywags.",
+ "author": "mnriem",
+ "repository": "https://github.com/mnriem/spec-kit-presets",
+ "download_url": "https://github.com/mnriem/spec-kit-presets/releases/download/pirate-v1.0.0/pirate.zip",
+ "homepage": "https://github.com/mnriem/spec-kit-presets",
+ "documentation": "https://github.com/mnriem/spec-kit-presets/blob/main/pirate/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.1.0"
+ },
+ "provides": {
+ "templates": 6,
+ "commands": 9
+ },
+ "tags": [
+ "pirate",
+ "theme",
+ "fun",
+ "experimental"
+ ]
+ },
+ "screenwriting": {
+ "name": "Screenwriting",
+ "id": "screenwriting",
+ "version": "1.0.0",
+ "description": "Spec-Driven Development for screenwriting/scriptwriting/tutorials: feature films, television (pilot, episode, limited series), and stage plays. Adapts the Spec Kit workflow to screenplay craft \u2014 slug lines, action lines, act breaks, beat sheets, and industry-standard pitch documents replace prose fiction conventions. Supports three-act, Save the Cat, TV pilot, network episode, cable/streaming episode, and stage-play structural frameworks.",
+ "author": "Andreas Daumann",
+ "repository": "https://github.com/adaumann/speckit-preset-screenwriting",
+ "download_url": "https://github.com/adaumann/speckit-preset-screenwriting/archive/refs/tags/v1.0.0.zip",
+ "homepage": "https://github.com/adaumann/speckit-preset-screenwriting",
+ "documentation": "https://github.com/adaumann/speckit-preset-screenwriting/blob/main/screenwriting/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.5.0"
+ },
+ "provides": {
+ "templates": 26,
+ "commands": 32,
+ "scripts": 1
+ },
+ "tags": [
+ "writing",
+ "screenplay",
+ "scriptwriting",
+ "film",
+ "tv",
+ "fountain",
+ "fountain-format",
+ "beat-sheet",
+ "teleplay",
+ "drama",
+ "comedy",
+ "storytelling",
+ "tutorial",
+ "education"
+ ],
+ "created_at": "2026-04-23T08:00:00Z",
+ "updated_at": "2026-04-23T08:00:00Z"
+ },
+ "security-governance": {
+ "name": "Security Governance",
+ "id": "security-governance",
+ "version": "0.2.0",
+ "description": "Adds secure development governance, MSL preference, ASVS verification, supply-chain transparency, and EU CRA awareness.",
+ "author": "Thorsten Hindermann",
+ "repository": "https://github.com/hindermath/spec-kit-preset-security-governance",
+ "download_url": "https://github.com/hindermath/spec-kit-preset-security-governance/archive/refs/tags/v0.2.0.zip",
+ "homepage": "https://github.com/hindermath/spec-kit-preset-security-governance",
+ "documentation": "https://github.com/hindermath/spec-kit-preset-security-governance/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.8.0"
+ },
+ "provides": {
+ "templates": 12,
+ "commands": 3
+ },
+ "tags": [
+ "security",
+ "governance",
+ "msl",
+ "asvs",
+ "supply-chain"
+ ],
+ "created_at": "2026-04-27T00:00:00Z",
+ "updated_at": "2026-04-27T00:00:00Z"
+ },
+ "spec2cloud": {
+ "name": "Spec2Cloud",
+ "id": "spec2cloud",
+ "version": "1.1.0",
+ "description": "Spec-driven workflow tuned for shipping to Azure: spec \u2192 plan \u2192 tasks \u2192 implement \u2192 deploy.",
+ "author": "Azure Samples",
+ "repository": "https://github.com/Azure-Samples/Spec2Cloud",
+ "download_url": "https://github.com/Azure-Samples/Spec2Cloud/releases/download/spec-kit-spec2cloud-v1.1.0/preset.zip",
+ "homepage": "https://aka.ms/spec2cloud",
+ "documentation": "https://github.com/Azure-Samples/Spec2Cloud/blob/main/spec-kit/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.1.0"
+ },
+ "provides": {
+ "templates": 5,
+ "commands": 8
+ },
+ "tags": [
+ "azure",
+ "spec2cloud",
+ "workflow",
+ "deployment"
+ ],
+ "created_at": "2026-04-30T00:00:00Z",
+ "updated_at": "2026-04-30T00:00:00Z"
+ },
+ "toc-navigation": {
+ "name": "Table of Contents Navigation",
+ "id": "toc-navigation",
+ "version": "1.0.0",
+ "description": "Adds a navigable Table of Contents to generated spec.md, plan.md, and tasks.md documents",
+ "author": "Quratulain-bilal",
+ "repository": "https://github.com/Quratulain-bilal/spec-kit-preset-toc-navigation",
+ "download_url": "https://github.com/Quratulain-bilal/spec-kit-preset-toc-navigation/archive/refs/tags/v1.0.0.zip",
+ "homepage": "https://github.com/Quratulain-bilal/spec-kit-preset-toc-navigation",
+ "documentation": "https://github.com/Quratulain-bilal/spec-kit-preset-toc-navigation/blob/main/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.4.0"
+ },
+ "provides": {
+ "templates": 3,
+ "commands": 3
+ },
+ "tags": [
+ "navigation",
+ "toc",
+ "documentation"
+ ]
+ },
+ "vscode-ask-questions": {
+ "name": "VS Code Ask Questions",
+ "id": "vscode-ask-questions",
+ "version": "1.0.0",
+ "description": "Enhances the clarify command to use vscode/askQuestions for batched interactive questioning, reducing API request costs in GitHub Copilot.",
+ "author": "fdcastel",
+ "repository": "https://github.com/fdcastel/spec-kit-presets",
+ "download_url": "https://github.com/fdcastel/spec-kit-presets/releases/download/vscode-ask-questions-v1.0.0/vscode-ask-questions.zip",
+ "homepage": "https://github.com/fdcastel/spec-kit-presets",
+ "documentation": "https://github.com/fdcastel/spec-kit-presets/blob/main/vscode-ask-questions/README.md",
+ "license": "MIT",
+ "requires": {
+ "speckit_version": ">=0.1.0"
+ },
+ "provides": {
+ "templates": 0,
+ "commands": 1
+ },
+ "tags": [
+ "vscode",
+ "askquestions",
+ "clarify",
+ "interactive"
+ ]
+ }
+ }
+}
\ No newline at end of file

diff --git a/.specify/presets/.cache/catalog-metadata.json b/.specify/presets/.cache/catalog-metadata.json
new file mode 100644
index 0000000000..06aa5b91f7
--- /dev/null
+++ b/.specify/presets/.cache/catalog-metadata.json
@@ -0,0 +1,4 @@
+{
+ "cached_at": "2026-05-21T18:52:11.763650+00:00",
+ "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.json"
+}
\ No newline at end of file

diff --git a/.specify/presets/.cache/catalog.json b/.specify/presets/.cache/catalog.json
new file mode 100644
index 0000000000..b890ea2b44
--- /dev/null
+++ b/.specify/presets/.cache/catalog.json
@@ -0,0 +1,30 @@
+{
+ "schema_version": "1.0",
+ "updated_at": "2026-04-24T00:00:00Z",
+ "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.json",
+ "presets": {
+ "lean": {
+ "name": "Lean Workflow",
+ "id": "lean",
+ "version": "1.0.0",
+ "description": "Minimal core workflow commands - just the prompt, just the artifact",
+ "author": "github",
+ "repository": "https://github.com/github/spec-kit",
+ "license": "MIT",
+ "bundled": true,
+ "requires": {
+ "speckit_version": ">=0.6.0"
+ },
+ "provides": {
+ "commands": 5,
+ "templates": 0
+ },
+ "tags": [
+ "lean",
+ "minimal",
+ "workflow",
+ "core"
+ ]
+ }
+ }
+}
\ No newline at end of file

diff --git a/.specify/templates/plan-template.md b/.specify/templates/plan-template.md
index f9d7d1560c..95faa73164 100644
--- a/.specify/templates/plan-template.md
+++ b/.specify/templates/plan-template.md
@@ -1,6 +1,7 @@
# Implementation Plan: [FEATURE]
**Branch**: `[###-feature-name]` | **Date**: [DATE] | **Spec**: [link]
+
**Input**: Feature specification from `/specs/[###-feature-name]/spec.md`
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/plan-template.md` for the execution workflow.
@@ -17,14 +18,22 @@
the iteration process.
-->
-**Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]
-**Primary Dependencies**: [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION]
-**Storage**: [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
-**Testing**: [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION]
+**Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]
+
+**Primary Dependencies**: [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION]
+
+**Storage**: [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
+
+**Testing**: [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION]
+
**Target Platform**: [e.g., Linux server, iOS 15+, WASM or NEEDS CLARIFICATION]
-**Project Type**: [e.g., library/cli/web-service/mobile-app/compiler/desktop-app or NEEDS CLARIFICATION]
-**Performance Goals**: [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION]
-**Constraints**: [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION]
+
+**Project Type**: [e.g., library/cli/web-service/mobile-app/compiler/desktop-app or NEEDS CLARIFICATION]
+
+**Performance Goals**: [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION]
+
+**Constraints**: [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION]
+
**Scale/Scope**: [domain-specific, e.g., 10k users, 1M LOC, 50 screens or NEEDS CLARIFICATION]
## Constitution Check

diff --git a/.specify/templates/spec-template.md b/.specify/templates/spec-template.md
index 16d5814f1e..849e38afff 100644
--- a/.specify/templates/spec-template.md
+++ b/.specify/templates/spec-template.md
@@ -1,9 +1,9 @@
# Feature Specification: [FEATURE NAME]
-**Feature Branch**: `[###-feature-name]`
-**Created**: [DATE]
-**Status**: Draft
-**Input**: User description: "$ARGUMENTS"
+**Feature Branch**: `[###-feature-name]`
+**Created**: [DATE]
+**Status**: Draft
+**Input**: User description: "$ARGUMENTS"
**Cross-Platform Spec**: <!-- Link to meshtastic/design/features/ spec, or "N/A — platform-specific only" with justification -->
## Summary
@@ -11,7 +11,7 @@
<!--
Provide a brief (2-3 sentence) summary of the feature, its purpose, and what
user problem it solves. Mention which modules are primarily affected.
-
+
CROSS-PLATFORM CHECK: Before writing this spec, check meshtastic/design/features/
for an existing cross-platform behavior spec. If one exists, this spec should describe
the Android-specific scope and acceptance criteria — not redefine the cross-platform
@@ -37,7 +37,7 @@
IMPORTANT: User stories should be PRIORITIZED as user journeys ordered by importance.
Each user story/journey must be INDEPENDENTLY TESTABLE - meaning if you implement just ONE of them,
you should still have a viable MVP (Minimum Viable Product) that delivers value.
-
+
Assign priorities (P1, P2, P3, etc.) to each story, where P1 is the most critical.
Think of each story as a standalone slice of functionality that can be:
- Developed independently
@@ -101,6 +101,22 @@
- What happens when [boundary condition]?
- How does system handle [error scenario]?
+## Requirements *(mandatory)*
+
+<!--
+ ACTION REQUIRED: The content in this section represents placeholders.
+ Fill them out with the right functional requirements.
+-->
+
+### Functional Requirements
+
+- **FR-001**: System MUST [specific capability]
+- **FR-002**: System MUST [specific capability]
+
+### Non-Functional Requirements
+
+- **NFR-001**: [Performance, accessibility, or quality requirement]
+
## Architecture
<!--
@@ -121,27 +137,11 @@
| [Component] | `feature/[name]/component/` | [Purpose] |
| [Existing Component] | `core/ui/component/` | [Reuse purpose] |
-## Requirements *(mandatory)*
-
-<!--
- ACTION REQUIRED: The content in this section represents placeholders.
- Fill them out with the right functional requirements.
--->
-
-### Functional Requirements
-
-- **FR-001**: System MUST [specific capability]
-- **FR-002**: System MUST [specific capability]
-
-### Non-Functional Requirements
-
-- **NFR-001**: [Performance, accessibility, or quality requirement]
-
## Source-Set Impact
<!--
ACTION REQUIRED: Identify which KMP source sets this feature affects.
- All business logic and UI MUST be in commonMain (Constitution §I, §III).
+ All business logic and UI MUST be in commonMain (Constitution I, III).
-->
| Source Set | Impact | Justification |
@@ -154,7 +154,7 @@
<!--
ACTION REQUIRED: Note any UI elements that must be reviewed against the
- Meshtastic Client Design Standards (Constitution §V). Flag intentional
+ Meshtastic Client Design Standards (Constitution V). Flag intentional
deviations with rationale.
-->
@@ -166,7 +166,7 @@
## Privacy Assessment
<!--
- ACTION REQUIRED: Confirm this feature does not violate Constitution §IV.
+ ACTION REQUIRED: Confirm this feature does not violate Constitution IV.
If the feature handles any sensitive data, document the safeguards.
-->

diff --git a/.specify/templates/tasks-template.md b/.specify/templates/tasks-template.md
index 927cb4e5aa..5bc9eb6f0b 100644
--- a/.specify/templates/tasks-template.md
+++ b/.specify/templates/tasks-template.md
@@ -6,6 +6,7 @@ description: "Task list template for feature implementation"
# Tasks: [FEATURE NAME]
**Input**: Design documents from `/specs/[###-feature-name]/`
+
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/
**Tests**: The examples below include test tasks. New automated tests are OPTIONAL and
@@ -31,21 +32,21 @@ touched modules before work is considered complete.
- **Mobile**: `api/src/`, `ios/src/` or `android/src/`
- Paths shown below assume single project - adjust based on plan.md structure
-<!--
+<!--
============================================================================
IMPORTANT: The tasks below are SAMPLE TASKS for illustration purposes only.
-
+
The /speckit.tasks command MUST replace these with actual tasks based on:
- User stories from spec.md (with their priorities P1, P2, P3...)
- Feature requirements from plan.md
- Entities from data-model.md
- Endpoints from contracts/
-
+
Tasks MUST be organized by user story so each story can be:
- Implemented independently
- Tested independently
- Delivered as an MVP increment
-
+
DO NOT keep these sample tasks in the generated tasks.md file.
============================================================================
-->

diff --git a/.specify/workflows/.cache/workflow-catalog-4beae448930d024d-meta.json b/.specify/workflows/.cache/workflow-catalog-4beae448930d024d-meta.json
new file mode 100644
index 0000000000..9b6a16b8ad
--- /dev/null
+++ b/.specify/workflows/.cache/workflow-catalog-4beae448930d024d-meta.json
@@ -0,0 +1 @@
+{"url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.community.json", "fetched_at": 1779389640.9802408}
\ No newline at end of file

diff --git a/.specify/workflows/.cache/workflow-catalog-4beae448930d024d.json b/.specify/workflows/.cache/workflow-catalog-4beae448930d024d.json
new file mode 100644
index 0000000000..56738d4750
--- /dev/null
+++ b/.specify/workflows/.cache/workflow-catalog-4beae448930d024d.json
@@ -0,0 +1,6 @@
+{
+ "schema_version": "1.0",
+ "updated_at": "2026-04-10T00:00:00Z",
+ "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.community.json",
+ "workflows": {}
+}
\ No newline at end of file

diff --git a/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7-meta.json b/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7-meta.json
new file mode 100644
index 0000000000..8dd7d8a85e
--- /dev/null
+++ b/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7-meta.json
@@ -0,0 +1 @@
+{"url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.json", "fetched_at": 1779389641.039055}
\ No newline at end of file

diff --git a/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7.json b/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7.json
new file mode 100644
index 0000000000..e37d6ad510
--- /dev/null
+++ b/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7.json
@@ -0,0 +1,19 @@
+{
+ "schema_version": "1.0",
+ "updated_at": "2026-04-13T00:00:00Z",
+ "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.json",
+ "workflows": {
+ "speckit": {
+ "id": "speckit",
+ "name": "Full SDD Cycle",
+ "description": "Runs specify \u2192 plan \u2192 tasks \u2192 implement with review gates",
+ "author": "GitHub",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/speckit/workflow.yml",
+ "tags": [
+ "sdd",
+ "full-cycle"
+ ]
+ }
+ }
+}
\ No newline at end of file

diff --git a/AGENTS.md b/AGENTS.md
index 1d20691fa6..48c7c75d91 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -49,5 +49,4 @@ You are an expert Android/KMP engineer. Maintain architectural boundaries, use M
<!-- SPECKIT START -->
For additional context about technologies to be used, project structure,
shell commands, and other important information, read the current plan
-at `specs/20260520-153504-udp-label-rename/plan.md`
<!-- SPECKIT END -->

Served by rngit 1.5.4 - Generated in 0.2s